package MuleBackend;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.Border;


/**
 * Class that deals with auctioning land and goods
 * controls 
 * Q- UP  A- DOWN
 * E- UP  D- DOWN
 * T- UP  G- DOWN
 * U- UP  J- DOWN
 * Good auction Only:
 * b- Make Transaction
 *
 * @author Nitinv
 *
 */
public class AuctionPanel extends JPanel{

//	GUI STUFF
	private JLabel titleLabel;
//	private JLabel[] priceLabel;
	private JLabel[] goodsLabel;
	private JLabel[] storeLabel;
	Border raisedborder, lowerborder;
//	private JLabel imageLabel;
	
// 	Land Auction Variables
	private boolean landAuction, goodAuction;
	private int highBid, winner;
	private int[] bid;
	private Land landForSale;
	
//Good Auction and Land Auction variable
	private ArrayList<Player> players;
	
//	Good Auction Variables
	private ArrayList<Player> buyingPlayers;
	private ArrayList<Player> sellingPlayers;
	private Town town;
	private Player lowSellingPlayer;
	private Player highBuyingPlayer;
	private int[] goodUnits;
	private int[] bids;
	private int[] sellPrices;
	private int lowestSellPrice;
	private int highestBid;
	private int maxPrice, leastPrice;
	private int lenPlayers;
	private int speed;
//	Static variables	
	static int goodType=-1;
	static int phase = 0;
	
	public AuctionPanel(){
		setLayout(null);
		landAuction = false;
		goodAuction = true;
//		priceLabel = new JLabel[4];
		goodsLabel = new JLabel[4];
		storeLabel = new JLabel[4];
		bid = new int[4];
		landForSale = null;
		buildGUI();
	}
	
	/**************************** INIT METHODS *******************************/
	
	public void buildGUI(){
		
		titleLabel = new JLabel("Auction",JLabel.CENTER);
		titleLabel.setFont(new java.awt.Font("Tahoma", 0, 24));
		titleLabel.setBounds(300,0,300,30);
		
//		priceLabel[0] = new JLabel("Buy");
//		priceLabel[0].setFont(new java.awt.Font("Tahoma", 0, 18));
//		priceLabel[0].setBounds(200,400,50,20);
//		priceLabel[1] = new JLabel("Buy");
//		priceLabel[1].setFont(new java.awt.Font("Tahoma", 0, 18));
//		priceLabel[1].setBounds(350,400,50,20);
//		priceLabel[2] = new JLabel("Buy");
//		priceLabel[2].setFont(new java.awt.Font("Tahoma", 0, 18));
//		priceLabel[2].setBounds(500,400,50,20);
//		priceLabel[3] = new JLabel("Buy");
//		priceLabel[3].setFont(new java.awt.Font("Tahoma", 0, 18));
//		priceLabel[3].setBounds(650,400,50,20);
		
		raisedborder = BorderFactory.createRaisedBevelBorder();
		lowerborder = BorderFactory.createLoweredBevelBorder();
		Border compound = BorderFactory.createCompoundBorder(raisedborder, lowerborder);
		goodsLabel[0] = new JLabel("0",JLabel.CENTER);
		goodsLabel[0].setBorder(compound);
		goodsLabel[0].setFont(new java.awt.Font("Tahoma", 0, 18));
		goodsLabel[0].setBounds(200,450,50,40);
		goodsLabel[1] = new JLabel("0",JLabel.CENTER);
		goodsLabel[1].setBorder(compound);
		goodsLabel[1].setFont(new java.awt.Font("Tahoma", 0, 18));
		goodsLabel[1].setBounds(350,450,50,40);
		goodsLabel[2] = new JLabel("0",JLabel.CENTER);
		goodsLabel[2].setBorder(compound);
		goodsLabel[2].setFont(new java.awt.Font("Tahoma", 0, 18));
		goodsLabel[2].setBounds(500,450,50,40);
		goodsLabel[3] = new JLabel("0",JLabel.CENTER);
		goodsLabel[3].setBorder(compound);
		goodsLabel[3].setFont(new java.awt.Font("Tahoma", 0, 18));
		goodsLabel[3].setBounds(650,450,50,40);
		
		storeLabel[0] = new JLabel("0",JLabel.CENTER);
		storeLabel[0].setBorder(compound);
		storeLabel[0].setFont(new java.awt.Font("Tahoma", 0, 18));
		storeLabel[0].setBounds(25,40,100,25);
		storeLabel[1] = new JLabel("0",JLabel.CENTER);
		storeLabel[1].setBorder(compound);
		storeLabel[1].setFont(new java.awt.Font("Tahoma", 0, 18));
		storeLabel[1].setBounds(25,65,100,50);
		storeLabel[2] = new JLabel("0",JLabel.CENTER);
		storeLabel[2].setBorder(compound);
		storeLabel[2].setFont(new java.awt.Font("Tahoma", 0, 18));
		storeLabel[2].setBounds(25,340,100,50);
		
		
		add(titleLabel);
//		add(priceLabel[0]);
//		add(priceLabel[1]);
//		add(priceLabel[2]);
//		add(priceLabel[3]);
		add(goodsLabel[0]);
		add(goodsLabel[1]);
		add(goodsLabel[2]);
		add(goodsLabel[3]);
		add(storeLabel[0]);
		add(storeLabel[1]);
		add(storeLabel[2]);
		
	}
	
	public void paint(Graphics g){
		super.paint(g);
		g.setColor(Color.gray);
		g.drawLine(150,100,150,380);
		g.drawLine(300,100,300,380);
		g.drawLine(450,100,450,380);
		g.drawLine(600,100,600,380);
		g.drawLine(750,100,750,380);
		
		g.setColor(Color.black);
		Graphics2D g2d = (Graphics2D) g;
		g2d.setStroke (new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1f, new float[] {2f}, 0f) );
		//g.drawLine(150, 380, 750, 380);
		if (landAuction){
			g.drawLine(150, 380, 750, 380);
		}
		if (goodAuction){
			//g.drawLine(150, 102, 750, 102);
			//g.drawLine(150, 380, 750, 380);
		}
	}
	
	/**************************** LAND AUCTION METHODS *******************************/
	
	public void landAuction(){
		landAuction = true;
		goodAuction = false;
		titleLabel.setText("Land Auction");

		for (int i=0; i<bid.length;i++){
			bid[i] = 0;
		}
		highBid = -1; winner = -1;
		
		for (int i=0; i<4;i++){
			if (i<GameDriver.game.getPlayerList().size()){
				goodsLabel[i].setText("");
			}else{
				goodsLabel[i].setVisible(false);
			}
		}
		storeLabel[0].setText("");
		storeLabel[1].setText("");
		storeLabel[2].setText("$"+landForSale.getPrice()*2);
		
		ArrayList<Player> tempPlayers = GameDriver.game.getPlayerList();
		players = new ArrayList<>();
		for(int k=0;k<tempPlayers.size();k++){
			int index = Player.returnIndexByID(tempPlayers,k+1);
			players.add(tempPlayers.get(index));
		}
//		timeAssigned = 4; //preferably multiple of 4
//		tc.setCounter(timeAssigned);
//		timer.start();
	}
	
	public int getBid(int playerIDNumber){
		return bid[playerIDNumber];
	}
	
	/**
	 * this method set the land color after the auction
	 */
	public void setWinner(){
//		GameDriver.game.getBoardGUI().colorLand(landForSale, GameDriver.game.getPlayerList().get(winner));
		if(winner == -1 || highBid < landForSale.getPrice()*2){			
			GameDriver.game.getBoardGUI().colorLand(landForSale, null);
		}
		else{
			System.out.println("WINNER of land auction is " + winner);
			GameDriver.game.getPlayerList().get(winner).addLand(landForSale);
			GameDriver.game.getPlayerList().get(winner).deductMoney(highBid);
			landForSale.setOwner(GameDriver.game.getPlayerList().get(winner));
			GameDriver.game.getBoardGUI().colorLand(landForSale, GameDriver.game.getPlayerList().get(winner));
		}
		for (int i=0; i<bid.length;i++){
			bid[i] = 0;
		}
		highBid = -1; winner = -1;
//		GameDriver.game.getStages().startStage(GameDriver.game.getStages().getCurrentStage() + 1);
	}
	
	public boolean isPlayerLandValid(int yLocation , int num,int playerIDNumber){
		if (num == 1){
			if (bid[playerIDNumber] < landForSale.getPrice()*2 && GameDriver.game.getPlayerList().get(playerIDNumber).hasMoney(landForSale.getPrice()*2)){
				bid[playerIDNumber] = landForSale.getPrice()*2;
			}else if (GameDriver.game.getPlayerList().get(playerIDNumber).hasMoney(bid[playerIDNumber]+10)){
				bid[playerIDNumber] = bid[playerIDNumber]+10;
			}
			if (bid[playerIDNumber]>highBid){
				highBid = bid[playerIDNumber];
				winner = playerIDNumber;
			}
			if (yLocation-10>=160)return true;
			else return false;
		}
		if (num == 2){
			if (bid[playerIDNumber]-10 < landForSale.getPrice()*2){
				bid[playerIDNumber] = 0;
			}else{
				bid[playerIDNumber] = bid[playerIDNumber]-10;
			}
			if (bid[winner]!=highBid){
				highBid = bid[playerIDNumber];
			}
			if (yLocation+10<=400 && bid[playerIDNumber]<=(landForSale.getPrice()*2+240))return true;
			else return false;
		}
		return false;
	}
	
	public void startLandAuction(Land landForSale){
		this.landForSale = landForSale;
		landAuction();
	}
	
	public Land getLandForSale(){
		return landForSale;
	}
	
	
	
	/**************************** GOOD AUCTION METHODS *******************************/
	
	/**
	 * Initialized all values to prepare for auction
	 * @param goods the title string to show what good is being auctioned
	 */
	public void goodAuction(String goods){
		landAuction = false;
		goodAuction = true;
		titleLabel.setText(goods+" Auction - Buy or Sell");
		
		for (int i=0; i<4;i++){
			if (i<GameDriver.game.getPlayerList().size()){
//				priceLabel[i].setText("Buy");
				goodsLabel[i].setText("");
			}else{
//				priceLabel[i].setVisible(false);
				goodsLabel[i].setVisible(false);
			}
		}
		
		//Initialize values
		town = GameDriver.game.getTown();
		goodType = (goodType+1)%4; //decides which good is being auctioned, increments each time this method is called
		town.setPrices();
		highestBid = 0;
		maxPrice = town.getMaxPrice(goodType);
		leastPrice = town.getMinPrice(goodType);
		highBuyingPlayer = null;
		lowSellingPlayer = null;
		phase = 1;
		players = GameDriver.game.getPlayerList();
		buyingPlayers = new ArrayList<>();
		for(int k=0;k<players.size();k++)
			buyingPlayers.add(players.get(k));
		sellingPlayers = new ArrayList<>();
		lenPlayers = buyingPlayers.size();
		goodUnits = new int[lenPlayers];
		for(int k=0;k<lenPlayers;k++)
			goodUnits[k]=0;
		bids = new int[lenPlayers]; //max buying players size
		sellPrices = new int[lenPlayers]; // max selling players size
		lowestSellPrice = maxPrice;
		for(int k=0;k<lenPlayers;k++)
			sellPrices[k]=lowestSellPrice;
		
		updateSpeedChange();
		storeLabel[0].setText("" + town.unitsToSell(goodType));
		storeLabel[1].setText("" + maxPrice);
		storeLabel[2].setText("" + leastPrice);
	}
	/**
	 * getter method for speed
	 * @return
	 */
	public int getSpeed(){
		return speed;
	}
	/**
	 * returns true if the player corresponding to the passed in player ID number is a buyer
	 * @param playerIDNumber
	 * @return
	 */
	public boolean isBuyer(int playerIDNumber){
		Player player = players.get(Player.returnIndexByID(players, playerIDNumber));
		if(buyingPlayers.contains(player))
			return true;
		return false;
	}
	/**
	 * returns true if the player corresponding to the passed in player ID number is a seller
	 * @param playerIDNumber
	 * @return
	 */
	public boolean isSeller(int playerIDNumber){
		Player player = players.get(Player.returnIndexByID(players, playerIDNumber));
		if(sellingPlayers.contains(player))
			return true;
		return false;
	}
	/**
	 * returns the bid for the good of the player
	 * @param playerIDNumber
	 * @return
	 */
	public int getGoodBid(int playerIDNumber){
		return bids[playerIDNumber];
	}
	/**
	 * returns the selling price of the good of the player
	 * @param playerIDNumber
	 * @return
	 */
	public int getGoodSellPrice(int playerIDNumber){
		return sellPrices[playerIDNumber];
	}
	/**
	 * updates the phase, ie. from the selection of bidding or selling to actually auctioning
	 */
	public void updatePhase(){
		/*
		 * This if statement is to prevent anything from happening when the stage before good auction stage calls on this method.
		 * the stage before calls this method because currentStage is decremented to keep the good auction stage running for multiple goods, and so
		 * in order to update phase, I needed to put an if statement for the stage before the good auction phase.
		 */
		if(phase==0) return;
		phase = 2;
		titleLabel.setText("Bid!");
		updateSpeedChange();
	}
	/**
	 * updates the speed so that players move appropriately on the board
	 * also changes with phase
	 */
	private void updateSpeedChange(){
		if(phase==1){
			speed = 260;
		}
		else{
			double yCordDifference= 260;
			double amountDifference = (maxPrice - leastPrice);
			double speedDifference = yCordDifference/amountDifference;
			speed = (int)speedDifference;
			System.out.println("Speed changed to " + speed);
		}
	}
	/**
	 * a simple testing function that shows the list of buying players and selling players
	 */
	public void showPlayerLists(){
		System.out.println("Buying Players");
		for(Player p: buyingPlayers){
			System.out.println(p.getName());
		}
		System.out.println("Selling Players");
		for(Player p: sellingPlayers){
			System.out.println(p.getName());
		}
	}
	
	/**
	 * updates bids and selling prices of the player and compares them to the rest of the players
	 * @param goUp true if the person is increasing his bid or price, false otherwise
	 * @param playerIDNumber the ID number of the player that is making the move
	 * @return
	 */
	public boolean isPlayerActionValid(boolean goUp, int playerIDNumber){
		boolean change = false;
		int x = Player.returnIndexByID(players, playerIDNumber);
		Player currentPlayer = players.get(x);
		if (goUp){
			if(phase==1){
				if(sellingPlayers.contains(currentPlayer)==false){
				//Adds player to list of selling players if he has sufficient assets
					int units = currentPlayer.unitsToSell(goodType);
					if(units>0){
						goodUnits[playerIDNumber-1]=units;
						sellingPlayers.add(currentPlayer);
						buyingPlayers.remove(currentPlayer);
						sellPrices[playerIDNumber-1] = maxPrice - 1;
						goodsLabel[playerIDNumber-1].setText("" + goodUnits[playerIDNumber-1]);
						change = true;
					}
				}
			}
			
			if(phase==2){
				if(buyingPlayers.contains(currentPlayer)){
					if(currentPlayer.hasMoney(leastPrice+1)){
						if(bids[playerIDNumber-1]==0 && leastPrice+1 <= lowestSellPrice){
							bids[playerIDNumber-1]=leastPrice+1;
							change = true;
						}
						else
						if(bids[playerIDNumber-1]<lowestSellPrice && currentPlayer.hasMoney(bids[playerIDNumber-1]+1)){
							bids[playerIDNumber-1]+=1;
							change = true;
						}
					}
					if(bids[playerIDNumber-1]>highestBid){
						highestBid=bids[playerIDNumber-1];
						highBuyingPlayer = currentPlayer;
					}
				}
				else
				if(sellingPlayers.contains(currentPlayer)){
					if(sellPrices[playerIDNumber-1]<maxPrice-1){
						sellPrices[playerIDNumber-1]+=1;
						change = true;
					}
					
					if(lowSellingPlayer == currentPlayer){
						Boolean sameSeller = true;
						for(int k=0;k<lenPlayers;k++){
							int index = Player.returnIndexByID(players, k+1);
							if(sellPrices[k]<sellPrices[playerIDNumber-1]){
								sameSeller = false;
								lowSellingPlayer = players.get(index);
								break;
							}
						}
						if(sameSeller == true){
							if(sellPrices[playerIDNumber-1]==maxPrice-1){
								lowestSellPrice = maxPrice-1;
								//If the lowest seller backs down, the next lowest seller is the losing player with the lowest price
								lowSellingPlayer = sellingPlayers.get(0);
							}
							else{
								lowestSellPrice+=1;
							}
						}
					}
					
				}
			}
		}
		else{
			if(phase==1){
				if(buyingPlayers.contains(currentPlayer)==false){
					buyingPlayers.add(currentPlayer);
					sellingPlayers.remove(currentPlayer);
					goodUnits[currentPlayer.getPlayerID()-1]=0;
					sellPrices[playerIDNumber-1] = maxPrice;
					goodsLabel[playerIDNumber-1].setText("" + goodUnits[playerIDNumber-1]);
					change = true;
				}
			}
			if(phase==2){
				if(buyingPlayers.contains(currentPlayer)){
					if(bids[playerIDNumber-1]==leastPrice+1){
						bids[playerIDNumber-1]=0;
						change = true;
					}
					else
					if(bids[playerIDNumber-1]==0);
					else{
						bids[playerIDNumber-1]-=1;
						change = true;
					}
				
					if(highBuyingPlayer == currentPlayer){
						Boolean sameBuyer = true;
						for(int k=0;k<lenPlayers;k++){
							int index = Player.returnIndexByID(players, k+1);
							if(bids[k]>bids[playerIDNumber-1]){
								sameBuyer = false;
								highBuyingPlayer = players.get(index);
							}
						}
						if(sameBuyer == true){
							if(bids[playerIDNumber-1]==0){
								highestBid = 0;
								highBuyingPlayer = null;
							}
							else
								highestBid-=1;
						}
					}
				}
				if(sellingPlayers.contains(currentPlayer)){
					if(sellPrices[playerIDNumber-1]>highestBid && sellPrices[x]>leastPrice){
						sellPrices[playerIDNumber-1]-=1;
						change = true;
					}
					if(sellPrices[playerIDNumber-1] < lowestSellPrice){
						lowestSellPrice = sellPrices[playerIDNumber-1];
						lowSellingPlayer = players.get(x);
					}
				}
			}
		}
		return change;
	}
	/**
	 * checks if the transaction made between players or player and town is valid
	 * also, updates player position if the selling player is out of goods to sell, or the buying player doesn't have enough money to buy more goods
	 * @return changingPlayerID is a array or size 2 that decides whether or not the players positions need to be updated after the transaction
	 * 
	 */
	public int[] isPurchaseValid(){
		int[] changingPlayerID = new int[2];
		changingPlayerID[0] = changingPlayerID[1] = -1;
		//There is a buying player and a selling player
		if(highBuyingPlayer!=null && lowSellingPlayer!=null){
			if(highestBid == lowestSellPrice){
				System.out.println("Transaction took place");
				int lowSellerInt = lowSellingPlayer.getPlayerID()-1;
				int highBuyerInt = highBuyingPlayer.getPlayerID()-1;
				highBuyingPlayer.addGood(goodType);
				lowSellingPlayer.deductGood(goodType);
				highBuyingPlayer.deductMoney(highestBid);
				lowSellingPlayer.addMoney(highestBid);
				System.out.println("Player "+ highBuyingPlayer.getName() + "bought from Player " + lowSellingPlayer.getName());
				goodUnits[lowSellerInt]--;
				goodUnits[highBuyerInt]++;
				goodsLabel[lowSellerInt].setText(""+ goodUnits[lowSellerInt]);
				goodsLabel[highBuyerInt].setText("" + goodUnits[highBuyerInt]);
				if(highBuyingPlayer.hasMoney(highestBid)==false){
					changingPlayerID[0] = highBuyerInt;
					bids[highBuyerInt] = 0;
					highBuyingPlayer = null;
					highestBid = 0;
					for(int k=0;k<players.size();k++){
						int index = Player.returnIndexByID(players, k+1);
						if(bids[k]>bids[highBuyerInt]){
							highBuyerInt = k;
							highBuyingPlayer = players.get(index);
							highestBid = bids[k];
						}
					}
				}
				if(goodUnits[lowSellerInt]==0){
					changingPlayerID[1] = lowSellerInt;
					sellingPlayers.remove(lowSellingPlayer);
					/*
					if(sellingPlayers.isEmpty() || buyingPlayers.isEmpty()){
						tc.setCounter(1);
					}
					*/
					sellPrices[lowSellerInt] = maxPrice;
					lowestSellPrice = maxPrice;
					lowSellingPlayer = null;
					for(int k=0;k<players.size();k++){
						int index = Player.returnIndexByID(players,k+1);
						if(sellPrices[k]<sellPrices[lowSellerInt]){
							lowSellingPlayer = players.get(index);
							lowestSellPrice = sellPrices[k];
							lowSellerInt = k;
						}
					}
				}
			}
		}
		
		else
		if(highBuyingPlayer!=null){
			if(highestBid == maxPrice && town.hasGood(goodType)){
				System.out.println("Transaction took place");
				highBuyingPlayer.addGood(goodType);
				town.deductGood(goodType);
				highBuyingPlayer.deductMoney(maxPrice);
				int highBuyerInt = highBuyingPlayer.getPlayerID()-1;
				goodUnits[highBuyerInt]++;
				goodsLabel[highBuyerInt].setText("" + goodUnits[highBuyerInt]);
				storeLabel[0].setText("" + town.unitsToSell(goodType));
				if(highBuyingPlayer.hasMoney(maxPrice)==false){
					changingPlayerID[0] = highBuyerInt;
					buyingPlayers.remove(highBuyingPlayer);
					bids[highBuyerInt] = 0;
					highestBid = 0;
					highBuyingPlayer = null;
					for(int k=0;k<players.size();k++){
						int index = Player.returnIndexByID(players, k+1);
						if(bids[k]>bids[highBuyerInt]){
							highBuyingPlayer = players.get(index);
							highestBid = bids[k];
							highBuyerInt = k;
						}
					}
		
				}
				
			}
		}
		else
		if(lowSellingPlayer!=null){
			if(lowestSellPrice == leastPrice){
				System.out.println("Transaction took place");
				town.addGood(goodType);
				lowSellingPlayer.deductGood(goodType);
				lowSellingPlayer.addMoney(leastPrice);
				int lowSellerInt = lowSellingPlayer.getPlayerID()-1;
				goodUnits[lowSellerInt]--;
				goodsLabel[lowSellerInt].setText("" + goodUnits[lowSellerInt]);
				if(goodUnits[lowSellerInt]==0){
					changingPlayerID[1] = lowSellerInt;
					sellingPlayers.remove(lowSellingPlayer);
					/*
					if(sellingPlayers.isEmpty()){
						tc.setCounter(1);
					}
					*/
					sellPrices[lowSellerInt] = maxPrice;
					lowestSellPrice = maxPrice;
					lowSellingPlayer = null;
					for(int k=0;k<players.size();k++){
						int index = Player.returnIndexByID(players, k+1);
						if(sellPrices[k]<sellPrices[lowSellerInt]){
							lowSellingPlayer = players.get(index);
							lowSellerInt = k;
							lowestSellPrice = sellPrices[k];
						}
					}
					/*
					if(lowSellingPlayer == null)
						tc.setCounter(1);
					*/
				}
			}
		}
		return changingPlayerID;
	}
	
}
